package com.bifrost.service.impl;

import com.bifrost.common.model.ResultModel;
import com.bifrost.common.util.HttpRequestUtils;
import com.bifrost.constant.*;
import com.bifrost.constant.OrderType;
import com.bifrost.entity.*;
import com.bifrost.exception.CouponBuyException;
import com.bifrost.model.ItemModel;
import com.bifrost.model.orderreturn.ReturnModel;
import com.bifrost.model.orderreturn.ReturnRequest;
import com.bifrost.repository.CouponDetailRepository;
import com.bifrost.repository.CouponRepository;
import com.bifrost.repository.MediaRepository;
import com.bifrost.repository.OrderItemRepository;
import com.bifrost.repository.OrderReturnRepository;
import com.bifrost.repository.ReturnMediaMapRepository;
import com.bifrost.service.BonusPointsService;
import com.bifrost.service.CountryAreaService;
import com.bifrost.service.ProductSkuService;
import com.bifrost.service.ReturnService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author rangf
 * @date 2018/3/6
 */
@Service
public class ReturnServiceImpl implements ReturnService {

    @Autowired
    OrderReturnRepository orderReturnRepository;
    @Autowired
    MediaRepository mediaRepository;
    @Autowired
    OrderItemRepository orderItemRepository;
    @Autowired
    ReturnMediaMapRepository returnMediaMapRepository;
    @Autowired
    ProductSkuService productSkuService;
    @Autowired
    CountryAreaService countryAreaService;
    @Autowired
    BonusPointsService bonusPointsService;
    @Autowired
    CouponDetailRepository couponDetailRepository;
    @Autowired
    CouponRepository couponRepository;

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyMMddHH");

    /**
     * 订单是否可以申请售后
     *
     * @param order
     * @return
     */
    @Override
    public boolean canReturn(Order order) {
        if (order != null) {
            if (OrderStatus.FINISHED.equals(order.getOrderStatus())) {
                /*单品退不用判断
                List<OrderReturn> returnList = findVaildRefundOrders(order.getOrderId());
                if (CollectionUtils.isEmpty(returnList)) {
                    return true;
                }*/
                return true;
            }
        }
        return false;
    }

    /**
     * 申请售后
     *
     * @param customer  customer
     * @param order     order
     * @param orderItem orderItem
     * @param request   request
     * @return 订单
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public OrderReturn apply(Customer customer, Order order, OrderItem orderItem, ReturnRequest request) {
        if(OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())){
            CouponDetail couponDetail = couponDetailRepository.findByCouponCode(orderItem.getCouponCode());
            if(couponDetail == null || couponDetail.getIsUsed() || couponDetail.getCustomer() == null){
                throw new CouponBuyException("该优惠券已使用，不能申请售后");
            }
        }
        Integer quantity = request.getQuantity();
        Integer skuQuantity = orderItem.getSkuQuantity();
        Integer returnQuantity = orderItem.getReturnQuantity();
        if(quantity.compareTo(skuQuantity) > 0)
            throw new RuntimeException("return quantity must less than or equal to skuQuantity");
        if(null != returnQuantity){
            if(returnQuantity.compareTo(skuQuantity) == 0)
                throw new RuntimeException("no available quantity can apply");
            if(returnQuantity.compareTo(skuQuantity) < 0)
                if (quantity.compareTo(skuQuantity - returnQuantity) > 0)
                    throw new RuntimeException("return quantity must less than available return quantity");
        }
        OrderReturn orderReturn = new OrderReturn();
        orderReturn.setCouponId(order.getCouponId());
        orderReturn.setCustomer(customer);
        orderReturn.setRelatedOrder(order);
        orderReturn.setReturnType(request.getReturnType());
        orderReturn.setShippingType(request.getShippingType());
        orderReturn.setMerchantStore(order.getMerchantStore());
        orderReturn.setStatus(OrderReturnStatus.PURCHASED);
        orderReturn.setCustomerMessage(request.getDesc());
        orderReturn.setSkuQuantity(quantity);
        orderReturn = saveOrderReturnMedia(orderReturn, request.getMedias());
        orderReturn.setCreatedTimestamp(new Date());
        orderReturn.setUpdatedTimestamp(new Date());
        orderReturn.setOrderReturnItems(new ArrayList<>());

        orderItem.setStatus(OrderItemStatus.RETURNING);
        if(null == returnQuantity || returnQuantity == 0)
            returnQuantity = 0;
        orderItem.setReturnQuantity(quantity + returnQuantity);
        orderItemRepository.save(orderItem);

        if (ReturnType.RETURN.equalsIgnoreCase(request.getReturnType())) {
            //订单类型为现金购买优惠券
            if(OrderType.CASH_BY_COUPON.equalsIgnoreCase(order.getOrderType())){
                orderReturn.setRefundTotal(order.getOrderTotal());
            }else {
                orderReturn.setRefundTotal(orderItem.getSkuPrice().multiply(new BigDecimal(quantity))
                        .subtract(orderItem.getDiscountShare())
                        .subtract(orderItem.getShipShare()));
            }
        }
        orderReturn = saveOrderReturnItem(orderReturn, orderItem, true);
        orderReturn = orderReturnRepository.save(orderReturn);
        orderReturn.setReturnNumber(String.format("%s%d%d", LocalDateTime.now().format(FORMATTER), order.getMerchantStore().getMerchantId(), orderReturn.getId()));
        return orderReturn;
    }

    /**
     * 申请售后 (整单)
     *
     * @param customer customer
     * @param order    order
     * @param request  request
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public OrderReturn applyAll(Customer customer, Order order, ReturnRequest request) {
        Assert.notNull(customer,"申请售后的用户信息为空");
        Assert.notNull(order,"订单信息为空");
        Assert.notNull(request,"售后详情为空");
        OrderReturn orderReturn = new OrderReturn();
        orderReturn.setCustomer(customer);
        orderReturn.setRelatedOrder(order);
        orderReturn.setReturnType(request.getReturnType());
        orderReturn.setShippingType(request.getShippingType());
        orderReturn.setMerchantStore(order.getMerchantStore());
        orderReturn.setStatus(OrderReturnStatus.PURCHASED);
        orderReturn.setCustomerMessage(request.getDesc());
        orderReturn = saveOrderReturnMedia(orderReturn, request.getMedias());
        orderReturn.setCreatedTimestamp(new Date());
        orderReturn.setUpdatedTimestamp(new Date());
        List<OrderItem> orderItems = order.getOrderItems();
        if(orderItems.isEmpty()){
            throw  new RuntimeException("订单项不能为空");
        }
        int skuQuantity = 0;
        List<OrderReturnItem> orderReturnItems = new ArrayList<OrderReturnItem>();
        BigDecimal bigDecimal = new BigDecimal(0);
        for (OrderItem orderItem : orderItems) {
            skuQuantity += orderItem.getSkuQuantity();
            if (StringUtils.isEmpty(orderItem.getStatus())) {
                orderItem.setStatus(OrderItemStatus.RETURNING);
                orderItemRepository.save(orderItem);
                bigDecimal.add(orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuQuantity())).subtract(orderItem.getDiscountShare())
                        .subtract(orderItem.getShipShare()));
                OrderReturnItem orderReturnItem = saveOrderReturnItemSingle(orderReturn, orderItem);
                orderReturnItems.add(orderReturnItem);
            }
        }
        if (ReturnType.RETURN.equalsIgnoreCase(request.getReturnType())) {
            orderReturn.setRefundTotal(bigDecimal);
        }
        orderReturn.setSkuQuantity(skuQuantity);
        orderReturn.setOrderReturnItems(orderReturnItems);
        orderReturn.setReturnNumber(String.format("%s%d%d", LocalDateTime.now().format(FORMATTER), order.getMerchantStore().getMerchantId(), orderReturn.getId()));
        orderReturnRepository.save(orderReturn);
        return orderReturn;
    }

    /**
     * 申请退货:保存订单项(整單)
     *
     * @param orderReturn orderReturn
     * @param item        item
     * @return 订单
     */
    public OrderReturnItem saveOrderReturnItemSingle(OrderReturn orderReturn, OrderItem item) {
        OrderReturnItem returnItem = new OrderReturnItem();
        ProductSku sku = productSkuService.getSkuById(item.getSkuId());
        returnItem.setSkuId(item.getSkuId());
        returnItem.setSkuName(item.getSkuName());
        returnItem.setSkuPrice(item.getSkuPrice());
        returnItem.setRetailPrice(sku.getRetailPrice());
        returnItem.setSkuQuantity(item.getSkuQuantity());
        returnItem.setOrderItemType(item.getOrderItemType());
        returnItem.setCategoryId(sku.getCategory().getCategoryId());
        returnItem.setProductId(sku.getProduct().getProductId());
        returnItem.setDiscountShare(item.getDiscountShare());
        returnItem.setShipShare(item.getDiscountShare());
        returnItem.setBonusPoints(item.getBonusPoints());
        returnItem.setOrderReturn(orderReturn);
        return returnItem;
    }

    /**
     * 申请退货:保存订单项
     *
     * @param orderReturn    orderReturn
     * @param item           item
     * @param isSingleReturn 是否单品退货
     * @return 订单
     */
    @Override
    public OrderReturn saveOrderReturnItem(OrderReturn orderReturn, OrderItem item, boolean isSingleReturn) {
        OrderReturnItem returnItem = new OrderReturnItem();
        // ProductSku sku = productSkuService.getSkuById(item.getSkuId());
        returnItem.setSkuId(item.getSkuId());
        returnItem.setCouponCode(item.getCouponCode());
        returnItem.setSkuName(item.getSkuName());
        returnItem.setSkuPrice(item.getSkuPrice());
        returnItem.setRetailPrice(item.getRetailPrice());
        if (isSingleReturn) {
            returnItem.setSkuQuantity(orderReturn.getSkuQuantity());
        } else {
            returnItem.setSkuQuantity(item.getSkuQuantity());
        }
        returnItem.setExternalId(item.getExternalId());
        returnItem.setSkuUPC(item.getSkuUPC());
        returnItem.setSkuCost(item.getSkuCost());
        returnItem.setOrderItemType(item.getOrderItemType());
        returnItem.setCategoryId(item.getCategoryId());
        returnItem.setProductId(item.getProductId());
        returnItem.setDiscountShare(item.getDiscountShare());
        returnItem.setShipShare(item.getDiscountShare());
        returnItem.setBonusPoints(item.getBonusPoints());
        returnItem.setOrderReturn(orderReturn);
        returnItem.setPromoApplied(item.isPromoApplied());
        returnItem.setAppliedPromoId(item.getAppliedPromoId());
        returnItem.setSupplierId(item.getSupplierId());
        //如果有服务
        /*if (Boolean.TRUE.equals(item.getHasService())) {
            returnItem.setHasService(Boolean.TRUE);
            List<OrderItemService> services = item.getOrderItemServices();
            returnItem.setOrderItemServices(new ArrayList<>());
            if (services != null && !services.isEmpty()) {
                services.forEach(service -> {
                    OrderItemService ois = new OrderItemService();
                    ois.setCurrencyCode(service.getCurrencyCode());
                    ois.setMerchantStore(service.getMerchantStore());
                    ois.setMerchantStoreName(service.getMerchantStoreName());
                    ois.setOrderItem(returnItem);
                    ois.setProductService(service.getProductService());
                    ois.setServiceName(service.getServiceName());
                    ois.setServicePrice(ois.getServicePrice());
                    returnItem.getOrderItemServices().add(ois);
                });
            }
        }*/
        //类型为礼品
        /*if (OrderItemType.GIFTWRAP.equalsIgnoreCase(item.getOrderItemType())) {
            returnItem.setHasGift(Boolean.TRUE);
            returnItem.setGiftwrapOrderItems(new ArrayList<>());
            List<GiftwrapOrderItem> giftWraps = item.getGiftwrapOrderItems();
            giftWraps.forEach(gidb -> {
                GiftwrapOrderItem gi = new GiftwrapOrderItem();
                gi.setOrderItem(returnItem);
                gi.setGiftName(gidb.getGiftName());
                gi.setProductSku(sku);
                gi.setQuantity(gidb.getQuantity());
                returnItem.getGiftwrapOrderItems().add(gi);
            });
            returnItem.setGiftwrapOrderItems(item.getGiftwrapOrderItems());
        }*/
        //类型为绑定 保存入库
        /*if (OrderItemType.BUNDLE.equalsIgnoreCase(item.getOrderItemType())) {
            List<OrderBundleItem> obs = item.getOrderBundleItems();
            returnItem.setOrderBundleItems(new ArrayList<>());
            if (obs != null && !obs.isEmpty()) {
                obs.forEach(ob -> {
                    OrderBundleItem refundOb = new OrderBundleItem();
                    refundOb.setItemQuantity(ob.getItemQuantity());
                    refundOb.setOrder(order);
                    refundOb.setOrderItem(returnItem);
                    refundOb.setProduct(ob.getProduct());
                    refundOb.setProductSku(ob.getProductSku());
                    refundOb.setRetailPrice(ob.getRetailPrice());
                    refundOb.setSalePrice(ob.getSalePrice());
                    item.getOrderBundleItems().add(refundOb);
                });
            }

        }*/
        orderReturn.getOrderReturnItems().add(returnItem);
        return orderReturn;
    }

    private OrderReturn saveOrderReturnMedia(OrderReturn orderReturn, String mediaIds) {
        if (StringUtils.isNotEmpty(mediaIds)) {
            orderReturn.setReturnMediaMaps(new ArrayList<>());
            String[] mediaIdArray = mediaIds.split(",");
            for (String mediaId : mediaIdArray) {
                Media media = mediaRepository.findOne(Long.valueOf(mediaId));
                if (media != null) {
                    orderReturn.setHasImages(Boolean.TRUE);
                    ReturnMediaMap returnMediaMap = new ReturnMediaMap();
                    returnMediaMap.setMedia(media);
                    returnMediaMap.setOrderReturn(orderReturn);
                    orderReturn.getReturnMediaMaps().add(returnMediaMap);
                }
            }
        }
        return orderReturn;
    }

    /**
     * 撤销售后
     *
     * @param customer customer
     * @param returnId 售后单Id
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean cancel(Customer customer, Long returnId) {
        OrderReturn orderReturn = orderReturnRepository.getByIdAndCustomerId(returnId, customer.getCustomerId());
        if (orderReturn != null) {
            if (OrderReturnStatus.PURCHASED.equals(orderReturn.getStatus()) || OrderReturnStatus.CONFIRMED.equals(orderReturn.getStatus())) {
                orderReturn.setStatus(OrderReturnStatus.CANCELED);
                orderReturnRepository.save(orderReturn);
                /*List<Long> skuIds = orderReturn.getOrderReturnItems().stream().map(OrderReturnItem::getSkuId).collect(Collectors.toList());
                for (Long skuId : skuIds) {
                    orderItemRepository.updateOrderItemStatus(orderReturn.getRelatedOrder().getOrderId(), skuId);
                }*/
                List<OrderReturnItem> orderReturnItemList = orderReturn.getOrderReturnItems();
                if (CollectionUtils.isNotEmpty(orderReturnItemList)) {
                    for (OrderReturnItem orderReturnItem : orderReturnItemList) {
                        Long skuId = orderReturnItem.getSkuId();
                        Integer quantity = orderReturnItem.getSkuQuantity();
                        orderItemRepository.updateOrderItemReturnQUantity(orderReturn.getRelatedOrder().getOrderId(), skuId, quantity);
                    }
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 售后：邮寄商品
     *
     * @param customer   customer
     * @param returnId   returnId
     * @param shipNumber shipNumber
     * @return
     */
    @Override
    public boolean deliver(Customer customer, Long returnId, String shipNumber) {
        OrderReturn orderReturn = orderReturnRepository.getByIdAndCustomerId(returnId, customer.getCustomerId());
        if (orderReturn != null) {
            if (OrderReturnStatus.CONFIRMED.equals(orderReturn.getStatus()) && ReturnShippingType.DELIVERY.equals(orderReturn.getShippingType())) {
                orderReturn.setShippingModuleCode(shipNumber);
                orderReturn.setStatus(OrderReturnStatus.SHIPPED);
                orderReturnRepository.save(orderReturn);
                return true;
            }
        }
        return false;
    }

    /**
     * 获取所有售后单
     *
     * @param merchantStore
     * @param page
     * @param pageSize
     * @param customer
     * @param status
     * @return
     */
    @Override
    public List<ReturnModel> orders(MerchantStore merchantStore, Integer page, Integer pageSize, Customer customer, String status) {
        Pageable pageable = new PageRequest(page - 1, pageSize, new Sort(Sort.Direction.DESC, "updatedTimestamp"));
        Specification<OrderReturn> query = new Specification<OrderReturn>() {
            @Override
            public Predicate toPredicate(Root<OrderReturn> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                if (StringUtils.isNotEmpty(status)) {
                    predicates.add(cb.equal(root.get("Status"), status));
                }
                if (merchantStore != null) {
                    predicates.add(cb.equal(root.get("merchantStore"), merchantStore));
                }
                predicates.add(cb.equal(root.get("customer"), customer));
                Predicate[] p = new Predicate[predicates.size()];
                return cb.and(predicates.toArray(p));
            }
        };
        Page<OrderReturn> data = orderReturnRepository.findAll(query, pageable);
        if (data.hasContent()) {
            List<OrderReturn> returnList = data.getContent();
            if (returnList != null && !returnList.isEmpty()) {
                List<ReturnModel> orders = new ArrayList<>();
                for (OrderReturn orderReturn : returnList) {
                    orders.add(convertToReturnModel(orderReturn, true));
                }
                return orders;
            }
            return null;
        }
        return null;
    }

    /**
     * @param orderReturn
     * @param isUsedToList
     * @return
     */
    private ReturnModel convertToReturnModel(OrderReturn orderReturn, boolean isUsedToList) {
        ReturnModel returnModel = new ReturnModel();
        returnModel.setId(orderReturn.getId());
        returnModel.setReturnNumber(orderReturn.getReturnNumber());
        returnModel.setType(orderReturn.getReturnType());
        returnModel.setShippingType(orderReturn.getShippingType());
        returnModel.setStatus(orderReturn.getStatus());
        returnModel.setDesc(orderReturn.getCustomerMessage());
        returnModel.setCanceledReason(orderReturn.getCanceledReason());
        returnModel.setShipNumber(orderReturn.getShippingModuleCode());
        returnModel.setContact(orderReturn.getContact());
        returnModel.setContactPhone(orderReturn.getContactPhone());
        returnModel.setContactAddr(orderReturn.getContactAddress());
        returnModel.setShipName(orderReturn.getDeliveryLastName());
        returnModel.setShipPhone(orderReturn.getDeliveryTelephonePrimary());
        returnModel.setShipAddr(countryAreaService.getAddrDetail(orderReturn.getDeliveryState(),
                orderReturn.getDeliveryCity(), orderReturn.getDeliveryDistrict(), orderReturn.getDeliveryStreet()));
        returnModel.setApplyTime(orderReturn.getCreatedTimestamp());
        List<OrderReturnItem> orderReturnItemList = orderReturn.getOrderReturnItems();
        if (orderReturnItemList != null && !orderReturnItemList.isEmpty()) {
            if (isUsedToList) {
                returnModel.setItemModel(convertToItemModel(orderReturnItemList.get(0)));
            }
            if (!isUsedToList) {
                returnModel.setItemModels(new ArrayList<>());
                for (OrderReturnItem returnItem : orderReturnItemList) {
                    returnModel.getItemModels().add(convertToItemModel(returnItem));
                }
            }
        }
        if (OrderReturnStatus.PURCHASED.equals(orderReturn.getStatus()) || OrderReturnStatus.CONFIRMED.equalsIgnoreCase(orderReturn.getStatus())) {
            returnModel.setCanCancel(true);
        }
        if (OrderReturnStatus.CONFIRMED.equalsIgnoreCase(orderReturn.getStatus())) {
            returnModel.setCanDeliver(true);
        }
        return returnModel;
    }

    private ItemModel convertToItemModel(OrderReturnItem orderReturnItem) {
        ProductSku sku = productSkuService.getSkuById(orderReturnItem.getSkuId());
        if (sku != null) {
            ItemModel model = new ItemModel();
            //优惠券退单sku名称和图片改为优惠券信息
            String orderType = orderReturnItem.getOrderReturn().getRelatedOrder().getOrderType();
            if(OrderType.CASH_BY_COUPON.equalsIgnoreCase(orderType)){
                CouponDetail couponDetail = couponDetailRepository.findByCouponCode(orderReturnItem.getCouponCode());
                if(couponDetail != null){
                    model.setSkuName(couponDetail.getCouponName() + "[" + couponDetail.getCouponCode() + "]");
                }
                Media media = couponRepository.findOne(orderReturnItem.getOrderReturn().getCouponId()).getMedia();
                model.setImageUrl(media ==null?null: HttpRequestUtils.getUrl(media.getUrl()));
            }else {
                model.setSkuName(sku.getSkuName());
                model.setImageUrl(productSkuService.getDefaultSkuMedia(sku));
            }
            model.setSalePrice(orderReturnItem.getSkuPrice());
            model.setQuantity(orderReturnItem.getSkuQuantity());
            return model;
        }
        return null;
    }

    /**
     * 获取退货单明细
     *
     * @param returnId returnId
     * @return
     */
    @Override
    public ReturnModel order(Long returnId) {
        OrderReturn orderReturn = findById(returnId);
        if (orderReturn != null) {
            /*单品退：isUsedToList为true
            //ReturnModel returnModel = convertToReturnModel(orderReturn, false);*/
            ReturnModel returnModel = convertToReturnModel(orderReturn, true);
            Boolean hasImages = orderReturn.getHasImages();
            if (Boolean.TRUE.equals(hasImages)) {
                returnModel.setImages(new ArrayList<>());
                List<ReturnMediaMap> mediaMapList = returnMediaMapRepository.getAllByorderReturn(orderReturn);
                if (CollectionUtils.isNotEmpty(mediaMapList)) {
                    for (ReturnMediaMap returnMediaMap : mediaMapList) {
                        Media media = returnMediaMap.getMedia();
                        if (media != null) {
                            returnModel.getImages().add(HttpRequestUtils.getUrl(media.getUrl()));
                        }
                    }
                }
            }
            return returnModel;
        }
        return null;
    }

    /**
     * 查询所有有效售后
     *
     * @param orderId
     * @return
     */
    @Override
    public List<OrderReturn> findVaildRefundOrders(Long orderId) {
        if (orderId != null) {
            return orderReturnRepository.findVaildRefundOrders(orderId);
        }
        return null;
    }

    /**
     * 返回实体
     *
     * @param returnId
     * @return
     */
    @Override
    public OrderReturn findById(Long returnId) {
        if (returnId != null) {
            return orderReturnRepository.findOne(returnId);
        }
        return null;
    }

}
